#include "precompiled.h"
/*
 #include "precompiled.h"
//#include "myGlExtensions.h"

//#include "ModelLoader.h"
#include "TextureLoader.h"
#include "../include/glm/gtc/matrix_transform.hpp"
#include "../include/glm/gtc/type_ptr.hpp"

#include "UI_Manager.h"
#include "ModelLoader.h"
#include "AssetIOManager.h"

// Useful Globals.
double t0 = 0.0;
int frames = 0;
char titlestring[200];
static double shaderTime = 0.0;

// Shader things.
const char *vertexShaderStrings[1];		// Spaces to store our shader strings.
const char *fragmentShaderStrings[1];
GLhandleARB programObj;					// Shader objects.
GLhandleARB vertexShader;
GLhandleARB fragmentShader;
GLint myVertexShaderCompiled, myFragmentShaderCompiled,myShadersLinked;		// Compiled shader id's.
char str[4096]; // For error messages from the GLSL compiler and linker
static char* default_vertexShader = "default.vp";
static char* default_fragmentShader = "default.fp";

// Framebuffer/Renderbuffer/Colorbuffer things.
GLuint fbo[1], depth_rb[1], colorbo[1];

// Our Buffer Objects handles.
GLuint	vao[1], vbo_vertex[1], index_buffer[1];

// UI Stuff.
static UI_Manager *ui_man;

typedef struct{
	GLfloat x,y,z;		// Vertex.
	GLuint color;	// Color.
} spicyVertex;

Model m1, m2;
Texture t1,tCB;

// View, Project, Transformations
static glm::mat4 mProjection;
static glm::mat4 mCam;
static glm::mat4 mModel;
static glm::mat4 mMVP;

// Uniform locations
static GLint uniform_MVP = -1;
static GLint uniform_TextureColor = -1;
static GLint uniform_ScreenBuff = -1;
static GLint uniform_DoFSQ = -1;
static GLfloat uniform_time = -1;

//
 * loadExtensions() - Load OpenGL extensions for anything above OpenGL
 * We need to load functionality from extensions... Mandatory stuff!
 
void loadExtensions() {
    //These extension strings indicate that the OpenGL Shading Language,
    // version 1.00, and GLSL shader objects are supported.
    if(!glfwExtensionSupported("GL_ARB_shading_language_100"))
    {
        printError("GL init error", "GL_ARB_shading_language_100 extension was not found");
        return;
    }
    if(!glfwExtensionSupported("GL_ARB_shader_objects"))
    {
        printError("GL init error", "GL_ARB_shader_objects extension was not found");
        return;
    }
	else
	{
		glActiveTexture			  = (PFNGLACTIVETEXTUREPROC)glfwGetProcAddress("glActiveTexture");
		glCreateProgramObjectARB  = (PFNGLCREATEPROGRAMOBJECTARBPROC)glfwGetProcAddress("glCreateProgramObjectARB");
		glDeleteObjectARB         = (PFNGLDELETEOBJECTARBPROC)glfwGetProcAddress("glDeleteObjectARB");
		glUseProgramObjectARB     = (PFNGLUSEPROGRAMOBJECTARBPROC)glfwGetProcAddress("glUseProgramObjectARB");
		glCreateShaderObjectARB   = (PFNGLCREATESHADEROBJECTARBPROC)glfwGetProcAddress("glCreateShaderObjectARB");
		glShaderSourceARB         = (PFNGLSHADERSOURCEARBPROC)glfwGetProcAddress("glShaderSourceARB");
		glCompileShaderARB        = (PFNGLCOMPILESHADERARBPROC)glfwGetProcAddress("glCompileShaderARB");
		glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)glfwGetProcAddress("glGetObjectParameterivARB");
		glAttachObjectARB         = (PFNGLATTACHOBJECTARBPROC)glfwGetProcAddress("glAttachObjectARB");
		glGetInfoLogARB           = (PFNGLGETINFOLOGARBPROC)glfwGetProcAddress("glGetInfoLogARB");
		glLinkProgramARB          = (PFNGLLINKPROGRAMARBPROC)glfwGetProcAddress("glLinkProgramARB");
		glGetUniformLocationARB   = (PFNGLGETUNIFORMLOCATIONARBPROC)glfwGetProcAddress("glGetUniformLocationARB");
		glUniform4fARB            = (PFNGLUNIFORM4FARBPROC)glfwGetProcAddress("glUniform4fARB");
		glUniform1fARB            = (PFNGLUNIFORM1FARBPROC)glfwGetProcAddress("glUniform1fARB");
		glUniform1iARB            = (PFNGLUNIFORM1IARBPROC)glfwGetProcAddress("glUniform1iARB");

		// LOL holy sh-- is this tedious. 
		glUniformMatrix4fv            = (PFNGLUNIFORMMATRIX4FVPROC)glfwGetProcAddress("glUniformMatrix4fv");
		glBindAttribLocationARB				= (PFNGLBINDATTRIBLOCATIONARBPROC)glfwGetProcAddress("glBindAttribLocationARB");
		glGenVertexArrays					= (PFNGLGENVERTEXARRAYSPROC)glfwGetProcAddress("glGenVertexArrays");
		glBindVertexArray					= (PFNGLBINDVERTEXARRAYPROC)glfwGetProcAddress("glBindVertexArray");
		glDeleteVertexArrays				= (PFNGLDELETEVERTEXARRAYSPROC)glfwGetProcAddress("glDeleteVertexArrays");
		glGenBuffers						= (PFNGLGENBUFFERSARBPROC)glfwGetProcAddress("glGenBuffers");
		glBufferData						= (PFNGLBUFFERDATAARBPROC)glfwGetProcAddress("glBufferData");
		glBindBuffer						= (PFNGLBINDBUFFERARBPROC)glfwGetProcAddress("glBindBuffer");
		glBufferSubData						= (PFNGLBUFFERSUBDATAPROC)glfwGetProcAddress("glBufferSubData");
		glVertexAttribPointer				= (PFNGLVERTEXATTRIBPOINTERPROC)glfwGetProcAddress("glVertexAttribPointer");
		glEnableVertexAttribArray			= (PFNGLENABLEVERTEXATTRIBARRAYPROC)glfwGetProcAddress("glEnableVertexAttribArray");
		glUseProgram						= (PFNGLUSEPROGRAMPROC)glfwGetProcAddress("glUseProgram");
		glDisableVertexAttribArray			= (PFNGLDISABLEVERTEXATTRIBARRAYPROC)glfwGetProcAddress("glDisableVertexAttribArray");
		glDeleteProgram						= (PFNGLDELETEPROGRAMPROC)glfwGetProcAddress("glDeleteProgram");
		glDetachShader						= (PFNGLDETACHSHADERPROC)glfwGetProcAddress("glDetachShader");
		glDeleteBuffers						= (PFNGLDELETEBUFFERSPROC)glfwGetProcAddress("glDeleteBuffers");
		glDeleteShader						= (PFNGLDELETESHADERPROC)glfwGetProcAddress("glDeleteShader");
		glDrawRangeElements					= (PFNGLDRAWRANGEELEMENTSPROC)glfwGetProcAddress("glDrawRangeElements");

		glGenFramebuffersEXT					= (PFNGLGENFRAMEBUFFERSEXTPROC)glfwGetProcAddress("glGenFramebuffersEXT");
		glBindFramebufferEXT					= (PFNGLBINDFRAMEBUFFEREXTPROC)glfwGetProcAddress("glBindFramebufferEXT");
		glDeleteFramebuffersEXT					= (PFNGLDELETEFRAMEBUFFERSEXTPROC)glfwGetProcAddress("glDeleteFramebuffersEXT");
		glGenRenderbuffersEXT					= (PFNGLGENRENDERBUFFERSEXTPROC)glfwGetProcAddress("glGenRenderbuffersEXT");
		glRenderbufferStorageEXT					= (PFNGLRENDERBUFFERSTORAGEEXTPROC)glfwGetProcAddress("glRenderbufferStorageEXT");
		glBindRenderbufferEXT					= (PFNGLBINDRENDERBUFFEREXTPROC)glfwGetProcAddress("glBindRenderbufferEXT");
		glDeleteRenderbuffersEXT					= (PFNGLDELETERENDERBUFFERSEXTPROC)glfwGetProcAddress("glDeleteRenderbuffersEXT");
		glFramebufferTexture2DEXT					= (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)glfwGetProcAddress("glFramebufferTexture2DEXT");
		glFramebufferRenderbufferEXT					= (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)glfwGetProcAddress("glFramebufferRenderbufferEXT");
		glDrawBuffersARB					= (PFNGLDRAWBUFFERSARBPROC)glfwGetProcAddress("glDrawBuffersARB");
		glCheckFramebufferStatusEXT					= (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)glfwGetProcAddress("glCheckFramebufferStatusEXT");

		if( !glCreateProgramObjectARB || !glDeleteObjectARB || !glUseProgramObjectARB ||
			!glCreateShaderObjectARB || !glCreateShaderObjectARB || !glCompileShaderARB || 
			!glGetObjectParameterivARB || !glAttachObjectARB || !glGetInfoLogARB || 
			!glLinkProgramARB || !glGetUniformLocationARB || !glUniform4fARB ||
			!glUniform1fARB || !glUniform1iARB )
		{
			printError("GL init error", "One or more GL_ARB_shader_objects functions were not found");
			return;
		}
	}

	// Set the extensions to our classes.
	Texture::set_ptrGlActiveTexture( &glActiveTexture );
	Texture::set_ptrglUniform1i( &glUniform1iARB );
}

//
 * showFPS() - Calculate and report frames per second
 * (updated once per second) in the window title bar
 
void showFPS() {

    double t, fps;
    
    // Get current time
    t = glfwGetTime();  // Gets number of seconds since glfwInit()
    // If one second has passed, or if this is the very first frame
    if( (t-t0) > 1.0 || frames == 0 )
    {
        fps = (double)frames / (t-t0);
        sprintf(titlestring, "OpenGL Harness (%.1f FPS)", fps);
        glfwSetWindowTitle(titlestring);
        t0 = t;
        frames = 0;
    }
    frames ++;
}

//
 * setupCamera() - set up the OpenGL projection and (model)view matrices
 
void setupCamera() {
	GLfloat flv = 45.0f;
	GLfloat aspect = 4.0f / 3.0f;
	GLfloat znear = 0.1f;
	GLfloat zfar = 100.0f;
	mProjection = glm::perspective(flv,aspect,znear,zfar);

	mCam = glm::lookAt(
		glm::vec3(0,0,10),
		glm::vec3(0,0,0),
		glm::vec3(0,1,0));
	mModel = glm::mat4(1.0f);
	mModel = glm::scale(
		mModel,
		glm::vec3(2.0f));
	mModel = glm::rotate(
		mModel,
		0.0f,
		 glm::vec3(1.0f,0.0f,0.0f));
	mModel = glm::translate(
		mModel,
		glm::vec3(-0.5,0,0));
	mMVP = mProjection * mCam * mModel;
	//mMVP = glm::mat4(1.0f);
}

//**********************************************************************
// Create our vertex array objects and vertex buffer objects.
 * The basic flow here is to 1) Obtain our geometry. 2) Allocate our
 * vertex buffer object for the geometry vertices. 3) Submit our vertex data 
 * for our vbo to the graphics device. 4) Allocate our vertex indices vbo. 
 * 5) Submit our index data to the graphics device. 6) Allocate our vertex
 * array object data. 7) Set our vertex vbo and index vbo to the vao.
 * 8) Set the vbo attributes to be fed into our shaders.
//**********************************************************************
void initializeBuffers(){
	
	// Create the geometry for our triangle.
	// Our vertex structure is defined to have 3 Glfloats and a Glubyte.
	// Notice how we define the color as a hex value ABGR.
	spicyVertex simple_triangle[3];
	// V0 - bottom
	simple_triangle[0].x = 0.0f;
	simple_triangle[0].y = -0.5f;
	simple_triangle[0].z = 0.0f;
	simple_triangle[0].color = 0xff0000ff;

	// V1 - top right
	simple_triangle[1].x = 0.5f;
	simple_triangle[1].y = 0.5f;
	simple_triangle[1].z = 0.0f;
	simple_triangle[1].color = 0xff00ff00;

	// V2 - top left
	simple_triangle[2].x = -0.5f;
	simple_triangle[2].y = 0.5f;
	simple_triangle[2].z = 0.0f;
	simple_triangle[2].color = 0xffff0000;

	// Setup the vertex buffer data.
		// Get OpenGL to create a single vertex buffer object for us.
	glGenBuffers(1, &vbo_vertex[0]);
		// "Activate" our vertex buffer.
	glBindBuffer(GL_ARRAY_BUFFER, vbo_vertex[0]);
		// Allocate the space required for our data in the vertex buffer.
	glBufferData(GL_ARRAY_BUFFER, 3*sizeof(spicyVertex), NULL , GL_STATIC_DRAW);
		// Submit our data to the graphics device.
	glBufferSubData(GL_ARRAY_BUFFER, 0, 3*sizeof(spicyVertex), simple_triangle);


	// Index setup
	GLushort indices[3];
	indices[0]=0;
	indices[1]=1;
	indices[2]=2;
	glGenBuffers(1, &index_buffer[0]);
		// For our indices we work with element array buffers.
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer[0]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3*sizeof(GLushort), NULL, GL_STATIC_DRAW);
	glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 3*sizeof(GLushort), indices);

	// By this point all of our data should be on the graphics device.

	// VAO setup.
	// The vertex array object works (in it's utility) like a display list.
	// We activate it, set some features of our vbo's, and deactivate it.
	// At a later date, we can just activate this vao and operate on all this
	// sweet vertex buffer data.
	glGenVertexArrays(1, &vao[0]);
	glBindVertexArray(vao[0]);

	// Bind the vertex buffer and setup pointers for the VAO.
	// This is setting the vertex buffer for the vao.
	glBindBuffer(GL_ARRAY_BUFFER, vbo_vertex[0]);
		// We want to plug our vertex data into our shader's attributes. The first
		// argument here is the attribute to feed that data into. The first shader
		// attibute is at 0, the next at 1, etc...Here we have position at 0,
		// nothing at 1, nothing at 2, color at 3.
		// The offset is straight forward, and basically tells OpenGL how far from
		// the start of the vertex we're at our chunk of data is. If position is first,
		// and is made up of 3 vertices, then thats a space of float_size * 3. This is
		// how far our next data chunk, color, is from the start of the vertex.
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(spicyVertex), BUFFER_OFFSET(0));
	glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(spicyVertex), BUFFER_OFFSET(sizeof(GLfloat)*3));
		// For this vbo, tell our vao that the following attributes are active/not-active.
	glEnableVertexAttribArray(0);
	glDisableVertexAttribArray(1);
	glDisableVertexAttribArray(2);
	glEnableVertexAttribArray(3);

	// Bind the index buffer for the VAO.
	// This is setting the index buffer to use with this vao.
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer[0]);

	// Cleanup.
	// This doesn't delete anything, but it does unset our states to prevent
	//	any thing getting muddled.
	glBindVertexArray(0);
	glDisableVertexAttribArray(0);
	glBindBuffer(GL_ARRAY_BUFFER,0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
}

//
 * readShaderFile(filename) - read a shader source string from a file
 
unsigned char* readShaderFile(const char *filename) {
    FILE *file = fopen(filename, "r");
    if(file == NULL)
    {
        printError("ERROR", "Cannot open shader file!");
  		  return 0;
    }
    int bytesinfile = filelength(fileno(file));
    unsigned char *buffer = (unsigned char*)malloc(bytesinfile+1);
    int bytesread = fread( buffer, 1, bytesinfile, file);
    buffer[bytesread] = 0; // Terminate the string with 0
    fclose(file);
    
    return buffer;
}

void create_default_shaders(){

	// Create the vertex shader.
	vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);

	unsigned char *vertexShaderAssembly = readShaderFile(default_vertexShader);
	vertexShaderStrings[0] = (char*)vertexShaderAssembly;
	glShaderSourceARB( vertexShader, 1, vertexShaderStrings, NULL );
	glCompileShaderARB( vertexShader);
	free((void *)vertexShaderAssembly);

	glGetObjectParameterivARB( vertexShader, GL_OBJECT_COMPILE_STATUS_ARB, 
		&myVertexShaderCompiled );
	if(myVertexShaderCompiled  == GL_FALSE)
	{
		glGetInfoLogARB(vertexShader, sizeof(str), NULL, str);
		printError("Vertex shader compile error", str);
	}

	// Create the fragment shader.
	fragmentShader = glCreateShaderObjectARB( GL_FRAGMENT_SHADER_ARB );

	unsigned char *fragmentShaderAssembly = readShaderFile( default_fragmentShader );
	fragmentShaderStrings[0] = (char*)fragmentShaderAssembly;
	glShaderSourceARB( fragmentShader, 1, fragmentShaderStrings, NULL );
	glCompileShaderARB( fragmentShader );
	free((void *)fragmentShaderAssembly);

	glGetObjectParameterivARB( fragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, 
		&myFragmentShaderCompiled );
	if(myFragmentShaderCompiled == GL_FALSE)
	{
		glGetInfoLogARB( fragmentShader, sizeof(str), NULL, str );
		printError("Fragment shader compile error", str);
	}

	// Create a program object and attach the two compiled shaders.
	programObj = glCreateProgramObjectARB();
	glAttachObjectARB( programObj, vertexShader );
	glAttachObjectARB( programObj, fragmentShader );


	// Bind attribute index 0 (coordinates) to in_Position and attribute index 1 (color) to in_Color 
	// Attribute locations must be setup before calling glLinkProgram. 
	glBindAttribLocationARB(programObj, 0, "in_Position");
	glBindAttribLocationARB(programObj, 1, "in_Normal"); 
	glBindAttribLocationARB(programObj, 2, "in_TexCoord"); 
	glBindAttribLocationARB(programObj, 3, "in_Color"); 

	// Link the program object and print out the info log.
	glLinkProgramARB( programObj );
	glGetObjectParameterivARB( programObj, GL_OBJECT_LINK_STATUS_ARB, &myShadersLinked );

	if( myShadersLinked == GL_FALSE )
	{
		glGetInfoLogARB( programObj, sizeof(str), NULL, str );
		printError("Shader Program object linking error...", str);
		exit(MYEXIT_FAILED_LINKSHADERS);
	}

	// Get uniform locations.
	uniform_MVP = glGetUniformLocationARB(programObj, "MVP");
}

//
 * createShaders() - create, load, compile and link the GLSL shader objects.
 
void createShaders() {
	  // Create the vertex shader.
    vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);

	  unsigned char *vertexShaderAssembly = readShaderFile("diffuse.vp");
    vertexShaderStrings[0] = (char*)vertexShaderAssembly;
    glShaderSourceARB( vertexShader, 1, vertexShaderStrings, NULL );
    glCompileShaderARB( vertexShader);
    free((void *)vertexShaderAssembly);

    glGetObjectParameterivARB( vertexShader, GL_OBJECT_COMPILE_STATUS_ARB, 
                               &myVertexShaderCompiled );
    if(myVertexShaderCompiled  == GL_FALSE)
  	{
	  	glGetInfoLogARB(vertexShader, sizeof(str), NULL, str);
		  printError("Vertex shader compile error", str);
  	}

  	// Create the fragment shader.
    fragmentShader = glCreateShaderObjectARB( GL_FRAGMENT_SHADER_ARB );

    unsigned char *fragmentShaderAssembly = readShaderFile( "diffuse.fp" );
    fragmentShaderStrings[0] = (char*)fragmentShaderAssembly;
    glShaderSourceARB( fragmentShader, 1, fragmentShaderStrings, NULL );
    glCompileShaderARB( fragmentShader );
    free((void *)fragmentShaderAssembly);

    glGetObjectParameterivARB( fragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, 
                               &myFragmentShaderCompiled );
    if(myFragmentShaderCompiled == GL_FALSE)
   	{
		  glGetInfoLogARB( fragmentShader, sizeof(str), NULL, str );
		  printError("Fragment shader compile error", str);
	}

    // Create a program object and attach the two compiled shaders.
    programObj = glCreateProgramObjectARB();
    glAttachObjectARB( programObj, vertexShader );
    glAttachObjectARB( programObj, fragmentShader );


	// Bind attribute index 0 (coordinates) to in_Position and attribute index 1 (color) to in_Color 
	// Attribute locations must be setup before calling glLinkProgram. 
	glBindAttribLocationARB(programObj, 0, "in_Position");
	glBindAttribLocationARB(programObj, 1, "in_Normal"); 
	glBindAttribLocationARB(programObj, 2, "in_TexCoord"); 
	glBindAttribLocationARB(programObj, 3, "in_Color"); 

    // Link the program object and print out the info log.
    glLinkProgramARB( programObj );
    glGetObjectParameterivARB( programObj, GL_OBJECT_LINK_STATUS_ARB, &myShadersLinked );

    if( myShadersLinked == GL_FALSE )
	{
		glGetInfoLogARB( programObj, sizeof(str), NULL, str );
		printError("Shader Program object linking error... Using default shaders.", str);

		create_default_shaders();
		return;
	}

	// Get uniform locations.
	uniform_MVP = glGetUniformLocationARB(programObj, "MVP");
	uniform_TextureColor = glGetUniformLocationARB(programObj, "colorMap");
	uniform_ScreenBuff = glGetUniformLocationARB(programObj, "screenBuffer");
	uniform_DoFSQ = glGetUniformLocationARB(programObj, "fsq");
	uniform_time = glGetUniformLocationARB(programObj, "time");
}

void checkFBOCompleteleness(){

	GLenum fboStat = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	if(fboStat != GL_FRAMEBUFFER_COMPLETE_EXT){

		switch(fboStat){

		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
			printError("FBO ERROR: ","GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT...");
			break;
		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
			printError("FBO ERROR: ","GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT...");
			break;
		case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
			printError("FBO ERROR: ","GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT...");
			break;
		case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
			printError("FBO ERROR: ","GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT...");
			break;
		case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
			printError("FBO ERROR: ","GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT...");
			break;
		case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
			printError("FBO ERROR: ","GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT...");
			break;
		case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
			printError("FBO ERROR: ","GL_FRAMEBUFFER_UNSUPPORTED_EXT...");
			break;
		default:
			printError("FBO ERROR: ","Incomplete...");
			break;
		}
	}
}

void init_framebuffers(){

}

// Render to Texture.
void set_fbo_render_pass(){
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo[0]);

	glActiveTexture(GL_TEXTURE1_ARB);
	glBindTexture(GL_TEXTURE_2D, colorbo[0]);
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
		GL_COLOR_ATTACHMENT0_EXT,
		GL_TEXTURE_2D, colorbo[0], 0);

	checkFBOCompleteleness();

}
// Render with Texture.
void set_framebuffers_render_pass(){
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo[0]);

	glEnable(GL_TEXTURE_2D);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
	glBindTexture(GL_TEXTURE_2D, colorbo[0]);
	glActiveTexture(GL_TEXTURE1_ARB);
	glUniform1iARB(uniform_ScreenBuff, GL_TEXTURE1_ARB);
}

void finish_Framebuffer_render_pass(){

	checkFBOCompleteleness();
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
	glBindTexture(GL_TEXTURE_2D, 0);
}

void fbo_oneshot(){
	int m_width = 512;
	int m_height= 512;
	// Create the FBO
	glGenFramebuffersEXT( 1, &fbo[0] );
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fbo[0] );


	// Create the Color Texture
	glGenTextures( 1, &colorbo[0] );
	glBindTexture( GL_TEXTURE_2D, colorbo[0] );
	glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8,
		m_width, m_height,
		0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, colorbo[0], 0 );

	// Now Depth texture
	glGenTextures( 1, &depth_rb[0] );
	glBindTexture( GL_TEXTURE_2D, depth_rb[0] );

	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );

	glTexImage2D( GL_TEXTURE_2D, 0,
		GL_DEPTH24_STENCIL8_EXT,
		m_width,
		m_height,
		0,
		GL_DEPTH_STENCIL_EXT,
		GL_UNSIGNED_INT_24_8_EXT,
		0 );

	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT,
		GL_DEPTH_ATTACHMENT_EXT,
		GL_TEXTURE_2D,
		depth_rb[0],
		0 );


	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT,
		GL_STENCIL_ATTACHMENT_EXT,
		GL_TEXTURE_2D,
		depth_rb[0], 0 );

	checkFBOCompleteleness();
}

void fbo_oneshot_2(){
	int TEXTURE_WIDTH = 512;
	int TEXTURE_HEIGHT = 512;

	// create a texture object
	glGenTextures(1, &colorbo[0]);
	glBindTexture(GL_TEXTURE_2D, colorbo[0]);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap generation included in OpenGL v1.4
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
	glBindTexture(GL_TEXTURE_2D, 0);
	tCB.set_texID(colorbo[0]);

	// create a framebuffer object, you need to delete them when program exits.
	glGenFramebuffersEXT(1, &fbo[0]);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo[0]);

	// create a renderbuffer object to store depth info
	// NOTE: A depth renderable image should be attached the FBO for depth test.
	// If we don't attach a depth renderable image to the FBO, then
	// the rendering output will be corrupted because of missing depth test.
	// If you also need stencil test for your rendering, then you must
	// attach additional image to the stencil attachement point, too.
	glGenRenderbuffersEXT(1, &depth_rb[0]);
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_rb[0]);
	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);

	// attach a texture to FBO color attachement point
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, colorbo[0], 0);

	// attach a renderbuffer to depth attachment point
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb[0]);

	//@ disable color buffer if you don't attach any color buffer image,
	//@ for example, rendering depth buffer only to a texture.
	//@ Otherwise, glCheckFramebufferStatusEXT will not be complete.
	//glDrawBuffer(GL_NONE);
	//glReadBuffer(GL_NONE);

	// check FBO status
	checkFBOCompleteleness();

	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

void update_uniforms(){
	// Possible uniforms.
	// http://www.opengl.org/sdk/docs/man/xhtml/glUniform.xml
	glUseProgramObjectARB( programObj );
	glUniformMatrix4fv(
		uniform_MVP, 1, GL_FALSE, &mMVP[0][0]); 
}

void reload_shaders(){

	GLuint oldProgram = programObj;

	// We need to create our shaders again.
	createShaders();
	update_uniforms();

	// We need to delete the old shaders.
	glDeleteProgram(oldProgram);
}

void update_MVP_View(){
	GLfloat angle = 0.4f;
	glm::vec3 axis = glm::vec3(0);
	bool do_update = false;

	if(glfwGetKey(GLFW_KEY_UP)){
		axis += glm::vec3(-1,0,0);
		do_update=true;
	}
	if(glfwGetKey(GLFW_KEY_DOWN)){
		axis +=glm::vec3(1,0,0);
		do_update=true;
	}
	if(glfwGetKey(GLFW_KEY_LEFT)){
		axis +=glm::vec3(0,-1,0);
		do_update=true;
	}
	if(glfwGetKey(GLFW_KEY_RIGHT)){
		axis +=glm::vec3(0,1,0);
		do_update=true;
	}

	if(do_update){
		mCam=glm::rotate(
			mCam,
			angle,
			axis);

		mMVP = mProjection*mCam*mModel;
		update_uniforms();
	}
}

// update the time we will use for our shaders.
void update_time(){
	GLdouble t = glfwGetTime() - t0;
	t *= 0.001;
	shaderTime = (shaderTime > 1.0)?0.0:shaderTime+t;

	//std::cout << "T: " << t << std::endl;
	//std::cout << "Shader time: " << shaderTime << std::endl;

	glUniform1fARB(uniform_time, shaderTime);
}

void Draw_Indexed_Model(Model m){
	glBindVertexArray(m.vao()[0]);
	int num = m.numIndices();
	glDrawRangeElements(GL_TRIANGLES,0, num,num , GL_UNSIGNED_SHORT, NULL);
	glBindVertexArray(0);
}

static void display(void){
	glUseProgramObjectARB( programObj );
	glUniform1iARB(uniform_DoFSQ,0);
	t1.Bind(0,uniform_TextureColor);
	Draw_Indexed_Model(m2);
}

static void display_fsq(void){
	glUseProgramObjectARB( programObj );
	glUniform1iARB(uniform_DoFSQ,1);
	Draw_Indexed_Model(m1);
}

static void render_with_fbo(){

	// set the rendering destination to FBO
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo[0]);

	// clear buffer
	glClearColor(0.0f,0.3f,0.6f,1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// draw geometry.
	display();

	// back to normal window-system-provided framebuffer
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // unbind

	// unbind the color buffer.
	glBindTexture(GL_TEXTURE_2D, 0);
}
static void render_normal(){
	// clear framebuffer
	glClearColor(0.0f,0.3f,0.6f,1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

	////glBindTexture(GL_TEXTURE_2D, colorbo[0]);
	//glActiveTexture(GL_TEXTURE1_ARB);
	//glUniform1iARB(uniform_ScreenBuff, 1);

	tCB.Bind(1,uniform_ScreenBuff);

	display_fsq();

	glBindTexture(GL_TEXTURE_2D, 0);
}

void cleanup(){
	delete ui_man;

	// Cleanup all the things we bound and allocated
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	glUseProgram(0);
	glDisableVertexAttribArray(0);
	glDisableVertexAttribArray(1);
	glDetachShader(programObj, myVertexShaderCompiled);
	glDetachShader(programObj, myFragmentShaderCompiled);
	glDeleteProgram(programObj);
	glDeleteShader(myVertexShaderCompiled);
	glDeleteShader(myFragmentShaderCompiled);
	glDeleteBuffers(2, vbo_vertex);
	glDeleteBuffers(2, index_buffer);
	glDeleteVertexArrays(1, vao);
}


int main_pristine_1(int argc, char *argv[]){
	int running = GL_TRUE;

	// Initialize GLFW.
	glfwInit();

	// Open the OpenGL window.
	if( !glfwOpenWindow( 640, 480, 8,8,8,8,32,0,GLFW_WINDOW)){
		// glfwOpenWindow failed, so quit the program.
		glfwTerminate();

		std::cout << "GLFW failed to open the glWindow.. Terminating." << std::endl;
		std::cin.get();

		return MYEXIT_FAILED_OPENWINDOW;
	}
	glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
	glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 3);

	//**********************************************************************

	// Start our Awesomium UI.
	ui_man = new UI_Manager(640,480);

	// Load the extensions for GLSL - note that this has to be done
	// *after* the window has been opened, or we won't have a GL context
	// to query for those extensions and connect to instances of them.
	loadExtensions();

	// Create our vbo and vao.
	initializeBuffers();

	// Test out our model class.
	ModelLoader::create_plane(m1);

	// Test our model loader.
	ModelLoader::load_myModel("../models/BLEND/mySuzanne.blend",m2);

	// Test our texture loader.
	TextureLoader::Init();
	TextureLoader::LoadTextureFromFile("h_galaxy.png",t1);

	// Create the two shaders.
	createShaders();

	// Create our FBO stuff.
	fbo_oneshot_2();

	// Enable back face culling and Z buffering.
	glEnable(GL_CULL_FACE); // Cull away all back facing polygons.
	glEnable(GL_DEPTH_TEST); // Use the Z buffer.

	// Set the clear color.
	glClearColor(0.0f,0.3f,0.6f,1.0f);


	// Set up the camera projection. (Currently only needs to be done once).
	setupCamera();

	// Update our uniforms. (Currently only needs to be done once).
	update_uniforms();

	TextureLoader::Init();

	// Attach our texture.
	t1.Bind(0,uniform_TextureColor);

	while(running){

		glEnable(GL_BLEND); //Enable alpha blending
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //Set the blend function

		// Calculate and update the frames per second (FPS) display.
		showFPS();

		// Give our shader program the time.
		update_time();

		// Clear the color and depth buffer.
		//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		// Draw our scene.
		render_with_fbo();
		render_normal();


		// Update/Draw our UI.
		ui_man->UpdateDraw();

		// Swap buffers, i.e. display the image and prepare for next frame.
		glfwSwapBuffers();

		// Check if the ESC key was pressed or if the window was closed.
		if( glfwGetKey(GLFW_KEY_ESC) || !glfwGetWindowParam(GLFW_OPENED)){
			running=GL_FALSE;
		}
		// Check to see if we should reload our shaders.
		else if( glfwGetKey(GLFW_KEY_ENTER) ){
			reload_shaders();
		}
		// Update our UI input.
		ui_man->GetInput();

		// Update our camera rotation.
		update_MVP_View();
	}

	cleanup();

	// Close the OpenGL window and terminate GLFW.
	glfwTerminate();

	return MYEXIT_SUCCESS;
}


int main(int argc, char *argv[]){

}
 */
 